package hamaster.jpbc.http;

import hamaster.jpbc.crypt.aes.AES;
import hamaster.jpbc.crypt.aes.OperationMode;
import hamaster.jpbc.crypt.aes.Rijndael;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Properties;

import javax.swing.JDialog;
import javax.swing.JOptionPane;

/**
 * 解密处理器
 * @author <a href="mailto:wangyeee@gmail.com">Wang Ye</a>
 */
public class DecryptionHandler implements HTTPResponseHandler {

	private JDialog container;
	private Properties response;
	private byte[] iv;
	private byte[] key;
	private volatile boolean handled;

	/**
	 * 创建一个解密处理器
	 * @param container 所在的容器
	 * @param iv 初始向量
	 * @param key 解密密钥
	 */
	public DecryptionHandler(JDialog container, byte[] iv, byte[] key) {
		response = new Properties();
		handled = false;
		this.iv = iv;
		this.key = key;
	}

	@Override
	public void handleHTTPResponse(HttpURLConnection conn) {
		final HttpURLConnection conn0 = conn;
		Thread t = new Thread() {
			public void run() {
				ByteArrayOutputStream out = new ByteArrayOutputStream();
				try {
					byte[] buffer = new byte[Rijndael.AES_BLOCK_SIZE];
					Arrays.fill(buffer, (byte) 0);
					InputStream in = conn0.getInputStream();
					int read = 0;
					while ((read = in.read(buffer)) > 0) {
						out.write(buffer, 0, read);
						Arrays.fill(buffer, (byte) 0);
					}
					in.close();
					conn0.disconnect();
				} catch (SocketTimeoutException e) {
					e.printStackTrace();
					JOptionPane.showMessageDialog(container, "网络访问超时，请检查网络连接", "错误", JOptionPane.ERROR_MESSAGE);
					return;
				} catch (IOException e) {
					e.printStackTrace();
					return;
				}
				byte[] responseData = out.toByteArray();
				byte[] larray = new byte[4];
				int i = 0;
				for (; i < responseData.length; i++) {
					if (responseData[i] != '\r' && responseData[i + 1] != '\n') {
						larray[i] = responseData[i];
					} else {
						break;
					}
				}
				byte[] iarray = new byte[i];
				System.arraycopy(larray, 0, iarray, 0, i);
				ByteBuffer b = ByteBuffer.wrap(iarray);
				int length = b.getInt();
				byte[] cipherArray = new byte[responseData.length - i - 2];
				System.arraycopy(responseData, i + 2, cipherArray, 0, cipherArray.length);
				AES aes = new AES();
				aes.setBlockSize(cipherArray.length);
				aes.setInitializationVector(iv);
				aes.setKey(key);
				aes.setOperationMode(OperationMode.CBC);
				byte[] dec = aes.decrypt(cipherArray);
				ByteArrayInputStream in = new ByteArrayInputStream(dec, 0, length);
				try {
					DecryptionHandler.this.response.load(in);
					DecryptionHandler.this.handled = true;
				} catch (IOException e) {
					e.printStackTrace();
					DecryptionHandler.this.response.clear();
				}
			}
		};
		t.start();
	}

	public Properties getResponse() {
		return response;
	}

	public void setIv(byte[] iv) {
		this.iv = iv;
	}

	public void setKey(byte[] key) {
		this.key = key;
	}

	public boolean hasHandled() {
		return handled;
	}
}
